<?php

namespace App\Console\Commands\Tasks;

use App\Models\ActivityDB\Love5202022GiftRank;
use App\Models\ActivityDB\Love5202022Setting;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;

class ScriptFixRoomRankCommand extends Command
{
    //命令名  房间code:修改类型
    protected $signature = 'script:fix_room_rank {arg?}';

    //命令描述:修复房间排行榜
    protected $description = 'fix room rank';

    public function __construct()
    {
        parent::__construct();
    }

    //业务处理
    public function handle()
    {
        $arg = $this->argument("arg");
        $argArr = explode(":", $arg);
        if(empty($argArr) || empty($argArr[1])){
            return $this->errorTips("请输入正确命令格式: [script:fix_room_rank 房间code:排行榜类型] (日榜: day,周榜: week,月榜: month");
        }
        $roomCode = $argArr[0];
        $type = $argArr[1];

        if(empty($roomCode)){
            return $this->errorTips("请选择房间");
        }

        // 获取房间id
        $roomId = app("model_user_room")->newQuery()->where("room_id", $roomCode)->value("id");
        if(!$roomId){
            return $this->errorTips("房间Code: {$roomCode} 不存在");
        }

        switch ($type){
            case "week":
                $this->infoTips("房间ID: {$roomId}, 房间Code: {$roomCode} 开始修复本周排行榜");
                $this->updateWeek($roomId);
                break;
            case "month":
                $this->infoTips("房间ID: {$roomId}, 房间Code: {$roomCode} 开始修复本月排行榜");
                $this->updateMonth($roomId);
                break;
            default:
                $this->infoTips("房间ID: {$roomId}, 房间Code: {$roomCode} 开始修复今日排行榜");
                $this->updateDay($roomId);
                break;
        }

        $this->successTips("修复完成");
    }


    public function updateDay(int $roomId)
    {
        $day = date('Ymd', time());
        $giveKey = "rank:rich:day:{$day}:{$roomId}";
        $acceptKey = "rank:charm:day:{$day}:{$roomId}";
        // 当前排行榜
        $giveRankScore = $this->getRank($giveKey);
        $this->infoTips("当前送礼排行榜: " . json_encode($giveRankScore));
        // 开始时间， 结束时间
        $start = Carbon::make(date("Y-m-d", time()))->startOfDay();
        $end = Carbon::make(date("Y-m-d", time()))->endOfDay();
        $this->infoTips("修复时间范围: {$start->toDateTimeString()}~{$end->toDateTimeString()}");
        // 获取送礼记录
        $roomUsersGiveScore = $this->getRoomUsersGiftScore($roomId, $start->timestamp, $end->timestamp)->pluck("score", "uid");
        $this->infoTips("今日房间用户送礼分值: " . $roomUsersGiveScore->toJson());
        foreach ($roomUsersGiveScore as $userId => $score){
            try{
                $rankScore = $giveRankScore[$userId];
                if($rankScore ==  $score){
                    continue;
                }
                app("redis")->zadd($giveKey, [ $userId => $score ]);
                $this->successTips("[送礼]用户ID: {$userId}, 排行分数: $rankScore, 修复分数: $score");
            }catch (\Exception $e){
                $this->errorTips("修复失败:" . $e->getMessage());
            }
        }

        $acceptRankScore = $this->getRank($acceptKey);
        $this->infoTips("当前收礼排行榜: " . json_encode($giveRankScore));
        $roomUsersAcceptScores = $this->getRoomUsersGiftScore($roomId, $start->timestamp, $end->timestamp, "accept")->pluck("score", "uid");
        $this->infoTips("房间用户收礼分值: " . $roomUsersGiveScore->toJson());
        foreach ($roomUsersAcceptScores as $userId => $score){
            try{
                $rankScore = $acceptRankScore[$userId];
                if($rankScore ==  $score){
                    continue;
                }
                app("redis")->zadd($acceptKey, [ $userId => $score ]);
                $this->successTips("[收礼]用户ID: {$userId}, 排行分数: $rankScore, 修复分数: $score");
            }catch (\Exception $e){
                $this->errorTips("修复失败:" . $e->getMessage());
            }
        }
    }

    public function updateWeek(int $roomId)
    {
        $week = date('oW', time());
        $giveKey = "rank:rich:week:{$week}:{$roomId}";
        $acceptKey = "rank:charm:week:{$week}:{$roomId}";
        // 当前排行榜
        $giveRankScore = $this->getRank($giveKey);
        $this->infoTips("当前送礼排行榜: " . json_encode($giveRankScore));
        // 开始时间， 结束时间
        $start = Carbon::make(date("Y-m-d", time()))->startOfWeek();
        $end = Carbon::make(date("Y-m-d", time()))->endOfWeek();
        $this->infoTips("修复时间范围: {$start->toDateTimeString()}~{$end->toDateTimeString()}");
        // 获取送礼记录
        $roomUsersGiveScore = $this->getRoomUsersGiftScore($roomId, $start->timestamp, $end->timestamp)->pluck("score", "uid");
        $this->infoTips("房间用户送礼分值: " . $roomUsersGiveScore->toJson());
        foreach ($roomUsersGiveScore as $userId => $score){
            try{
                $rankScore = $giveRankScore[$userId];
                if($rankScore ==  $score){
                    continue;
                }
                app("redis")->zadd($giveKey, [ $userId => $score ]);
                $this->successTips("[送礼]用户ID: {$userId}, 排行分数: $rankScore, 修复分数: $score");
            }catch (\Exception $e){
                $this->errorTips("修复失败:" . $e->getMessage());
            }
        }

        $acceptRankScore = $this->getRank($acceptKey);
        $this->infoTips("当前收礼排行榜: " . json_encode($giveRankScore));
        $roomUsersAcceptScores = $this->getRoomUsersGiftScore($roomId, $start->timestamp, $end->timestamp, "accept")->pluck("score", "uid");
        $this->infoTips("今日房间用户收礼分值: " . $roomUsersGiveScore->toJson());
        foreach ($roomUsersAcceptScores as $userId => $score){
            try{
                $rankScore = $acceptRankScore[$userId];
                if($rankScore ==  $score){
                    continue;
                }
                app("redis")->zadd($acceptKey, [ $userId => $score ]);
                $this->successTips("[收礼]用户ID: {$userId}, 排行分数: $rankScore, 修复分数: $score");
            }catch (\Exception $e){
                $this->errorTips("修复失败:" . $e->getMessage());
            }
        }
    }

    public function updateMonth(int $roomId)
    {
        $week = date('Ym', time());
        $giveKey = "rank:rich:month:{$week}:{$roomId}";
        $acceptKey = "rank:charm:month:{$week}:{$roomId}";
        // 当前排行榜
        $giveRankScore = $this->getRank($giveKey);
        $this->infoTips("当前送礼排行榜: " . json_encode($giveRankScore));
        // 开始时间， 结束时间
        $start = Carbon::make(date("Y-m-d", time()))->startOfMonth();
        $end = Carbon::make(date("Y-m-d", time()))->endOfMonth();
        $this->infoTips("修复时间范围: {$start->toDateTimeString()}~{$end->toDateTimeString()}");
        // 获取送礼记录
        $roomUsersGiveScore = $this->getRoomUsersGiftScore($roomId, $start->timestamp, $end->timestamp)->pluck("score", "uid");
        $this->infoTips("房间用户送礼分值: " . $roomUsersGiveScore->toJson());
        foreach ($roomUsersGiveScore as $userId => $score){
            try{
                $rankScore = $giveRankScore[$userId];
                if($rankScore ==  $score){
                    continue;
                }
                app("redis")->zadd($giveKey, [ $userId => $score ]);
                $this->successTips("[送礼]用户ID: {$userId}, 排行分数: $rankScore, 修复分数: $score");
            }catch (\Exception $e){
                $this->errorTips("修复失败:" . $e->getMessage());
            }
        }

        $acceptRankScore = $this->getRank($acceptKey);
        $this->infoTips("当前收礼排行榜: " . json_encode($giveRankScore));
        $roomUsersAcceptScores = $this->getRoomUsersGiftScore($roomId, $start->timestamp, $end->timestamp, "accept")->pluck("score", "uid");
        $this->infoTips("今日房间用户收礼分值: " . $roomUsersGiveScore->toJson());
        foreach ($roomUsersAcceptScores as $userId => $score){
            try{
                $rankScore = $acceptRankScore[$userId];
                if($rankScore ==  $score){
                    continue;
                }
                app("redis")->zadd($acceptKey, [ $userId => $score ]);
                $this->successTips("[收礼]用户ID: {$userId}, 排行分数: $rankScore, 修复分数: $score");
            }catch (\Exception $e){
                $this->errorTips("修复失败:" . $e->getMessage());
            }
        }
    }

    public function getRoomUsersGiftScore(int $roomId, int $start, int $end, string $type = "give")
    {
        $userField = $type == "give" ? "user_id" : "gift_user";
        return app("model_give_gift")
            ->newQuery()
            ->where("room_id", $roomId)
            ->where("add_time", ">=", $start)
            ->where("add_time", "<=", $end)
            ->groupBy([$userField])
            ->select([DB::raw("$userField as uid"), DB::raw("sum(total_price) as score")])
            ->get();
    }

    public function getRank($key)
    {
        return app("redis")->zrange($key, 0, -1, ['WITHSCORES' => true]);
    }

    public function infoTips(string $message)
    {
        echo "\033[33m [INFO]\033[0m    {$message}" . PHP_EOL;
        return true;
    }

    public function errorTips(string $message)
    {
        echo "\033[31m [ERROR]\033[0m   {$message}" . PHP_EOL;
        return false;
    }

    public function successTips(string $message)
    {
        echo "\033[32m [SUCCESS]\033[0m {$message}" . PHP_EOL;
        return true;
    }
}
